<html>

<head>
  <title>组对象Group、层级模型</title>
  <style>
    body {
      margin: 0;
    }

    canvas {
      display: block;
    }
  </style>
</head>

<body>
  <script src="./js/three.js"></script>
  <script src="./js/OrbitControls.js"></script>
  <script>
    // 1、创建场景
    var scene = new THREE.Scene();

    //创建一个球体几何对象
    // var geometry = new THREE.BoxGeometry(100, 100, 100);
    // ==============================================================================================================
    // 材质对象
    // var material = new THREE.MeshBasicMaterial({ color: 'pink' });
    // 网格模型对象Mesh
    // var mesh = new THREE.Mesh(geometry, material);
    // scene.add(mesh);//网格模型添加到场景中

    //创建两个网格模型mesh1、mesh2
    var geometry = new THREE.BoxGeometry(20, 20, 20);
    var material = new THREE.MeshLambertMaterial({ color: 0x0000ff });
    var group = new THREE.Group();
    var mesh1 = new THREE.Mesh(geometry, material);
    var mesh2 = new THREE.Mesh(geometry, material);
    // mesh2.translateX(25);
    //把mesh1型插入到组group中，mesh1作为group的子对象
    group.add(mesh1);
    //把mesh2型插入到组group中，mesh2作为group的子对象
    // group.add(mesh2);
    //把group插入到场景中作为场景子对象
    scene.add(group);

    //沿着Y轴平移mesh1和mesh2的父对象，mesh1和mesh2跟着平移
    // group.translateY(100);
    //父对象缩放，子对象跟着缩放
    // group.scale.set(4, 4, 4);
    //父对象旋转，子对象跟着旋转
    // group.rotateY(Math.PI / 6)
    // console.log('查看group的子对象', group.children);
    // console.log('查看Scene的子对象', scene.children);

    /* 
      .add()方法是给父对象添加一个子对象，.remove()方法是删除父对象中的一个子对象。
       一个对象的全部子对象可以通过该对象的.children()属性访问获得，
       执行该对象的删除方法.remove()和添加方法
       .add()一样改变的都是父对象的.children()属性。
     */
    // 删除父对象group的子对象网格模型mesh1
    // group.remove(mesh1)
    // 一次删除场景中多个对象
    // scene.remove(light, group)

    // 模型命名(.name属性)
    // group.add(mesh1)
    // 网格模型命名
    // mesh1.name = "眼睛"
    // mesh父对象对象命名
    // group.name = "头"

    // 头部网格模型和组
    var headMesh = sphereMesh(10, 0, 0, 0);
    headMesh.name = "脑壳"
    var leftEyeMesh = sphereMesh(1, 8, 5, 4);
    leftEyeMesh.name = "左眼"
    var rightEyeMesh = sphereMesh(1, 8, 5, -4);
    rightEyeMesh.name = "右眼"
    var headGroup = new THREE.Group();
    headGroup.name = "头部"
    headGroup.add(headMesh, leftEyeMesh, rightEyeMesh);
    // 身体网格模型和组
    var neckMesh = cylinderMesh(3, 10, 0, -15, 0);
    neckMesh.name = "脖子"
    var bodyMesh = cylinderMesh(14, 30, 0, -35, 0);
    bodyMesh.name = "腹部"
    var leftLegMesh = cylinderMesh(4, 60, 0, -80, -7);
    leftLegMesh.name = "左腿"
    var rightLegMesh = cylinderMesh(4, 60, 0, -80, 7);
    rightLegMesh.name = "右腿"
    var legGroup = new THREE.Group();
    legGroup.name = "腿"
    legGroup.add(leftLegMesh, rightLegMesh);
    var bodyGroup = new THREE.Group();
    bodyGroup.name = "身体"
    bodyGroup.add(neckMesh, bodyMesh, legGroup);
    // 人Group
    var personGroup = new THREE.Group();
    personGroup.name = "人"
    personGroup.add(headGroup, bodyGroup)
    personGroup.translateY(50)
    scene.add(personGroup);

    // 球体网格模型创建函数
    function sphereMesh(R, x, y, z) {
      var geometry = new THREE.SphereGeometry(R, 25, 25); //球体几何体
      var material = new THREE.MeshPhongMaterial({
        color: 0x0000ff
      }); //材质对象Material
      var mesh = new THREE.Mesh(geometry, material); // 创建网格模型对象
      mesh.position.set(x, y, z);
      return mesh;
    }
    // 圆柱体网格模型创建函数
    function cylinderMesh(R, h, x, y, z) {
      var geometry = new THREE.CylinderGeometry(R, R, h, 25, 25); //球体几何体
      var material = new THREE.MeshPhongMaterial({
        color: 0x0000ff
      }); //材质对象Material
      var mesh = new THREE.Mesh(geometry, material); // 创建网格模型对象
      mesh.position.set(x, y, z);
      return mesh;
    }


    // 递归遍历方法.traverse()
    scene.traverse(function (obj) {
      if (obj.type === "Group") {
        console.log(obj.name);
      }
      if (obj.type === "Mesh") {
        console.log('  ' + obj.name);
        obj.material.color.set(0xffff00);
      }
      if (obj.name === "左眼" | obj.name === "右眼") {
        obj.material.color.set(0x000000)
      }
      // 打印id属性
      console.log(obj.id);
      // 打印该对象的父对象
      console.log(obj.parent);
      // 打印该对象的子对象
      console.log(obj.children);
    })

    // 查找某个具体的模型
    // 遍历查找scene中复合条件的子对象，并返回id对应的对象
    var idNode = scene.getObjectById(4);
    console.log(idNode);

    // 遍历查找对象的子对象，返回name对应的对象（name是可以重名的，返回第一个）
    var nameNode = scene.getObjectByName("左腿");
    nameNode.material.color.set(0xff0000);

    // 声明一个三维向量用来保存世界坐标
    var worldPosition = new THREE.Vector3();
    // 执行getWorldPosition方法把模型的世界坐标保存到参数worldPosition中
    mesh1.getWorldPosition(worldPosition);






    // 3、光源设置：
    //环境光    环境光颜色与网格模型的颜色进行RGB进行乘法运算
    var ambient = new THREE.AmbientLight(0xffffff);
    scene.add(ambient);

    //点光源  
    var point = new THREE.PointLight(0xffffff);
    point.position.set(400, 200, 300);
    scene.add(point);


    // 4、添加相机
    var width = window.innerWidth; //窗口宽度
    var height = window.innerHeight; //窗口高度
    var k = width / height; //窗口宽高比
    var s = 200; //三维场景显示范围控制系数，系数越大，显示的范围越大
    var camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
    camera.position.z = 5;
    //设置相机位置
    camera.position.set(200, 300, 200);
    //设置相机方向(指向的场景对象)
    camera.lookAt(scene.position);


    // 5、创建渲染器对象
    var renderer = new THREE.WebGLRenderer();
    renderer.setSize(window.innerWidth, window.innerHeight);
    // renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色
    document.body.appendChild(renderer.domElement);

    // 6、执行渲染操作
    var animate = function () {
      renderer.render(scene, camera);
      requestAnimationFrame(animate);
      // personGroup.rotation.x += 0.01;
      // personGroup.rotation.y += 0.01;
    };
    animate();
    var controls = new THREE.OrbitControls(camera);//创建控件对象
  </script>
</body>

</html>